import { DatePart, UploadType } from "../TsEnums";
import { saveAs } from "file-saver";
import { FileExt, UrlFile } from "../Types";
import extIcon from "@/assets/fonts/exticonfont/extIcon";
import dayjs, { Dayjs } from "dayjs";
import isLeapYear from "dayjs/plugin/isLeapYear";
import "dayjs/locale/zh-cn";

dayjs.extend(isLeapYear); // 使用插件
dayjs.locale("zh-cn"); // 使用本地化语言

class GxBase {
    //图片格式扩展名
    static imageExts = ["png", "jpg", "jpeg", "gif", "bmp", "tiff", "pjp", "jfif", "svg", "xbm", "dib", "jxl", "svgz", "webp", "ico", "tif", "pjpeg", "avif"];

    //#region UUID
    /**
     * 生成全球唯一标识UUID
     * @returns UUID
     */
    public static GenerateUUID(): string {
        let d = new Date().getTime();
        if (window.performance && typeof window.performance.now === "function") {
            d += performance.now();
        }
        let uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
            let r = (d + Math.random() * 16) % 16 | 0;
            d = Math.floor(d / 16);
            return (c === "x" ? r : (r & 0x3) | 0x8).toString(16);
        });
        return uuid;
    }

    /**
     * 根据RCF4122检查字符串是否为UUID
     * @param uuid UUID
     * @returns
     */
    public static IsUUID(uuid: string): boolean {
        return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(uuid);
    }
    //#endregion

    //#region 序列化与反序列化
    /**
     * 将Json对象转换成Json字符串
     * @param jsonObj Json对象
     * @returns
     */
    public static SerializeObject(jsonObj: any): string {
        try {
            return JSON.stringify(jsonObj);
        } catch {
            return "";
        }
    }

    /**
     * 将Json字符串转换成Json对象
     * @param jsonStr Json字符串
     * @returns
     */
    public static DeserializeObject(jsonStr: string | null): any | null {
        if (this.IsEmpty(jsonStr)) {
            return null;
        }
        try {
            return JSON.parse(jsonStr as string);
        } catch {
            return null;
        }
    }

    /**
     * 深度Copy对象
     * @param obj 对象
     * @returns
     */
    public static DeepCopy(obj: any): any | null {
        return this.DeserializeObject(this.SerializeObject(obj));
    }
    //#endregion

    //#region Cookie Session LocalSession 的操作

    //#region Cookie
    /**
     * 将数据存储到Cookie中
     * @param key Cookie的名称
     * @param data Cookie的值
     */
    public static SetCookie(key: string, data: any): void {
        document.cookie = key + "=" + this.SerializeObject(data) + ";domain=" + Config._COOKIE_DOMAIN + ";path=/";
    }

    /**
     * 获取Cookie中的数据
     * @param key Cookie的名称
     * @returns
     */
    public static GetCookie(key: string): any | null {
        let name = key + "=";
        let allCookieStr = decodeURIComponent(document.cookie);
        let cookieArr = allCookieStr.split(";");
        for (let i = 0; i < cookieArr.length; i++) {
            let c = cookieArr[i];
            while (c.charAt(0) == " ") {
                c = c.substring(1);
            }
            if (c.indexOf(name) == 0) {
                return this.DeserializeObject(c.substring(name.length, c.length));
            }
        }
        return null;
    }

    /**
     * 移除指定Cookie中的数据
     * @param key Cookie的名称
     */
    public static RemoveCookie(key: string): void {
        document.cookie = key + "=; expires=Thu, 01 Jan 1970 00:00:01 GMT;";
        document.cookie = key + "=; expires=Thu, 01 Jan 1970 00:00:01 GMT;path=/";
    }

    /**
     * 移除所有Cookie中的数据
     */
    public static ClearCookie(): void {
        let keys = document.cookie.match(/[^ =;]+(?=\=)/g);
        if (!this.IsEmpty(keys) && (keys as RegExpExecArray).length > 0) {
            (keys as RegExpExecArray).forEach((key) => {
                this.RemoveCookie(key);
            });
        }
    }
    //#endregion

    //#region Session
    /**
     * 将数据存储到Session中
     * @param key Session的名称
     * @param data Session的值
     */
    public static SetSession(key: string, data: any): void {
        sessionStorage.setItem(key, this.SerializeObject(data));
    }

    /**
     * 获取Session中的数据
     * @param key Session的名称
     * @returns
     */
    public static GetSession(key: string): any | null {
        let strData = sessionStorage.getItem(key);
        if (this.IsEmpty(strData)) {
            return null;
        }
        return this.DeserializeObject(strData);
    }

    /**
     * 移除指定Session中的数据
     * @param key Session的名称
     */
    public static RemoveSession(key: string): void {
        sessionStorage.removeItem(key);
    }

    /**
     * 移除所有Session中的数据
     */
    public static ClearSession(): void {
        sessionStorage.clear();
    }
    //#endregion

    //#region LocalSession
    /**
     * 将数据存储到LocalSession中
     * @param key LocalSession的名称
     * @param data LocalSession的值
     */
    public static SetLocalSession(key: string, data: any): void {
        localStorage.setItem(key, this.SerializeObject(data));
    }

    /**
     * 获取LocalSession中的数据
     * @param key LocalSession的名称
     * @returns
     */
    public static GetLocalSession(key: string): any | null {
        let strData = localStorage.getItem(key);
        if (this.IsEmpty(strData)) {
            return null;
        }
        return this.DeserializeObject(strData);
    }

    /**
     * 移除指定LocalSession中的数据
     * @param key LocalSession的名称
     */
    public static RemoveLocalSession(key: string): void {
        localStorage.removeItem(key);
    }

    /**
     * 移除所有LocalSession中的数据
     */
    public static ClearLocalSession(): void {
        localStorage.clear();
    }
    //#endregion

    //#endregion

    //#region List与Tree的转换
    /**
     * 将List的数据转换成树形结构，子结点用children[]表示
     * @param list 源数据
     * @param idKey 主键名称
     * @param pidKey 父节点名称
     * @param isDelChildren 是否先删除list中的所有children
     * @returns
     */
    public static List2Tree(list: any[], idKey: string, pidKey: string = "parentID", isDelChildren: boolean = true): any[] {
        if (isDelChildren) {
            list.forEach((item) => {
                delete item.children;
            });
        }

        let map: any = {};
        list.forEach((item) => {
            map[item[idKey] || item.autoID] = item;
        });

        let res: any[] = [];

        for (let i = 0; i < list.length; i++) {
            let parent = map[list[i][pidKey]];

            if (parent) {
                (parent.children || (parent.children = [])).push(list[i]);
            } else {
                res.push(list[i]);
            }
        }

        return res;
    }

    /**
     * 将树形结构的数据转换成List
     * @param treeList 树形结构的数据
     * @returns
     */
    public static Tree2List(treeList: any[]): any[] {
        let queen: any[] = [],
            res: any[] = [];
        queen = queen.concat(treeList);
        while (queen.length) {
            let temp = queen.shift();
            if (temp.children) {
                queen = temp.children.concat(queen);
                delete temp["children"];
            }
            res.push(temp);
        }
        return res;
    }
    //#endregion

    //#region 小数的四则运算
    /**
     * 计算2个数的相加，用于处理小数精度问题
     * @param arg1 数字1
     * @param arg2 数字2
     * @returns
     */
    public static Jia(arg1: number, arg2: number): number {
        if (this.IsEmpty(arg1) || this.IsEmpty(arg2)) {
            return 0;
        }

        let r1, r2, m, c;
        try {
            r1 = arg1.toString().split(".")[1].length;
        } catch (e) {
            r1 = 0;
        }
        try {
            r2 = arg2.toString().split(".")[1].length;
        } catch (e) {
            r2 = 0;
        }
        c = Math.abs(r1 - r2);
        m = Math.pow(10, Math.max(r1, r2));
        if (c > 0) {
            let cm = Math.pow(10, c);
            if (r1 > r2) {
                arg1 = Number(arg1.toString().replace(".", ""));
                arg2 = Number(arg2.toString().replace(".", "")) * cm;
            } else {
                arg1 = Number(arg1.toString().replace(".", "")) * cm;
                arg2 = Number(arg2.toString().replace(".", ""));
            }
        } else {
            arg1 = Number(arg1.toString().replace(".", ""));
            arg2 = Number(arg2.toString().replace(".", ""));
        }
        return (arg1 + arg2) / m;
    }

    /**
     * 计算2个数的相减，用于处理小数精度问题
     * @param arg1 数字1
     * @param arg2 数字2
     * @returns
     */
    public static Jian(arg1: number, arg2: number): number {
        if (this.IsEmpty(arg1) || this.IsEmpty(arg2)) {
            return 0;
        }

        let r1, r2, m, n;
        try {
            r1 = arg1.toString().split(".")[1].length;
        } catch (e) {
            r1 = 0;
        }
        try {
            r2 = arg2.toString().split(".")[1].length;
        } catch (e) {
            r2 = 0;
        }
        m = Math.pow(10, Math.max(r1, r2));
        n = r1 >= r2 ? r1 : r2;
        return Number(((arg1 * m - arg2 * m) / m).toFixed(n));
    }

    /**
     * 计算2个数的相乘，用于处理小数精度问题
     * @param arg1 数字1
     * @param arg2 数字2
     * @returns
     */
    public static Cheng(arg1: number, arg2: number): number {
        if (this.IsEmpty(arg1) || this.IsEmpty(arg2)) {
            return 0;
        }
        let m = 0,
            s1 = arg1.toString(),
            s2 = arg2.toString();
        try {
            m += s1.split(".")[1].length;
        } catch (e) {}
        try {
            m += s2.split(".")[1].length;
        } catch (e) {}
        return (Number(s1.replace(".", "")) * Number(s2.replace(".", ""))) / Math.pow(10, m);
    }

    /**
     * 计算2个数的相除，用于处理小数精度问题
     * @param arg1 数字1
     * @param arg2 数字2
     * @returns
     */
    public static Chu(arg1: number, arg2: number): number {
        if (this.IsEmpty(arg1) || this.IsEmpty(arg2)) {
            return 0;
        }

        let t1 = 0,
            t2 = 0,
            r1,
            r2;
        try {
            t1 = arg1.toString().split(".")[1].length;
        } catch (e) {}
        try {
            t2 = arg2.toString().split(".")[1].length;
        } catch (e) {}

        r1 = Number(arg1.toString().replace(".", ""));
        r2 = Number(arg2.toString().replace(".", ""));
        return (r1 / r2) * Math.pow(10, t2 - t1);
    }
    //#endregion

    //#region 验证判断--字符串
    /**
     * 验证对象是否为（null,undefined,""）
     * @param obj js对象
     * @returns
     */
    public static IsEmpty(obj: any): boolean {
        if (obj == null || obj === "null" || obj === "undefined" || obj === "" || obj == undefined) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 正则验证
     * @param reg 正则表达式
     * @param str 验证的字符串
     * @returns
     */
    public static RegexMatch(reg: RegExp, str: string): boolean {
        return reg.test(str);
    }

    /**
     * 验证是否为邮箱
     * @param str 邮箱地址
     * @returns
     */
    public static IsEmail(str: string): boolean {
        if (this.IsEmpty(str)) {
            return false;
        }
        str = str.trim();
        let reg = /^([a-zA-Z0-9]+[_|\_|\.])*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.])*[a-zA-Z0-9]+\.[a-zA-Z]{2,10}$/;
        return this.RegexMatch(reg, str);
    }

    /**
     * 验证是否为手机号
     * @param str 手机号
     * @returns
     */
    public static IsMobile(str: string): boolean {
        if (this.IsEmpty(str)) {
            return false;
        }
        str = str.trim();
        let reg = /^1[3|4|5|6|7|8|9][0-9]{9}$/;
        return this.RegexMatch(reg, str);
    }

    /**
     * 验证是否为固定电话，可接受【区号-电话-分机】
     * @param str 固定电话
     * @returns
     */
    public static IsTel(str: string): boolean {
        if (this.IsEmpty(str)) {
            return false;
        }
        str = str.trim();
        let reg = /^((0\d{2,3})-)(\d{7,8})(-(\d{1,4}))?$/;
        return this.RegexMatch(reg, str);
    }

    /**
     * 验证是否为手机号和固话
     * @param str 手机号或固话
     * @returns
     */
    public static IsPhone(str: string): boolean {
        return this.IsMobile(str) || this.IsTel(str);
    }

    /**
     * 验证是否为IP地址
     * @param str IP地址
     * @returns
     */
    public static IsIp(str: string): boolean {
        if (this.IsEmpty(str)) {
            return false;
        }
        str = str.trim();
        let reg = /^(?:(?:1[0-9][0-9]\.)|(?:2[0-4][0-9]\.)|(?:25[0-5]\.)|(?:[1-9][0-9]\.)|(?:[0-9]\.)){3}(?:(?:1[0-9][0-9])|(?:2[0-4][0-9])|(?:25[0-5])|(?:[1-9][0-9])|(?:[0-9]))$/;
        return this.RegexMatch(reg, str);
    }

    /**
     * 验证是否为中文
     * @param str 字符串
     * @returns
     */
    public static IsChinese(str: string): boolean {
        if (this.IsEmpty(str)) {
            return false;
        }
        str = str.trim();
        let reg = /^[\u4e00-\u9fa5]{0,}$/;
        return this.RegexMatch(reg, str);
    }

    /**
     * 是否为字母
     * @param str 待验证的字符串
     * @returns
     */
    public static IsLetter(str: string): boolean {
        if (this.IsEmpty(str)) {
            return false;
        }
        str = str.trim();
        let reg = /^[A-Za-z]+$/;
        return this.RegexMatch(reg, str);
    }

    /**
     * 是否为字母与数字
     * @param str 待验证的字符串
     * @returns
     */
    public static IsLetterNumber(str: string): boolean {
        if (this.IsEmpty(str)) {
            return false;
        }
        str = str.trim();
        let reg = /^[A-Za-z0-9]+$/;
        return this.RegexMatch(reg, str);
    }
    //#endregion

    //#region 验证判断--数字
    /**
     * 验证是否为整数
     * @param  str 待验证的字符串
     * @returns
     */
    public static IsInt(str: string): boolean {
        if (this.IsEmpty(str)) {
            return false;
        }
        str = str.trim();
        let reg = /^-?\d+$/;
        return this.RegexMatch(reg, str);
    }

    /**
     * 验证是否为正整数 x>0
     * @param  str 待验证的字符串
     * @returns
     */
    public static IsIntPositive(str: string): boolean {
        if (this.IsEmpty(str)) {
            return false;
        }
        str = str.trim();
        let reg = /^\+?[1-9][0-9]*$/;
        return this.RegexMatch(reg, str);
    }

    /**
     * 验证是否为负整数 x<0
     * @param  str 待验证的字符串
     * @returns
     */
    public static IsIntNegative(str: string): boolean {
        if (this.IsEmpty(str)) {
            return false;
        }
        str = str.trim();
        let reg = /^\-[1-9][0-9]*$/;
        return this.RegexMatch(reg, str);
    }

    /**
     * 验证是否为正整数 x>=0
     * @param  str 待验证的字符串
     * @returns
     */
    public static IsIntPositiveByZero(str: string): boolean {
        if (this.IsEmpty(str)) {
            return false;
        }
        str = str.trim();
        let reg = /^\d+$/;
        return this.RegexMatch(reg, str);
    }

    /**
     * 验证是否为负整数 x<=0
     * @param  str 待验证的字符串
     * @returns
     */
    public static IsIntNegativeByZero(str: string): boolean {
        if (this.IsEmpty(str)) {
            return false;
        }
        str = str.trim();
        let reg = /^((-\d+)|(0+))$/;
        return this.RegexMatch(reg, str);
    }

    /**
     * 验证是否为数字
     * @param  str 待验证的字符串
     * @returns
     */
    public static IsNumber(str: string): boolean {
        if (this.IsEmpty(str)) {
            return false;
        }
        str = str.trim();
        let reg = /^-?\d+(\.\d+)?$/;
        return this.RegexMatch(reg, str);
    }

    /**
     * 验证是否为正数字 x>0
     * @param  str 待验证的字符串
     * @returns
     */
    public static IsNumberPositive(str: string): boolean {
        if (this.IsEmpty(str)) {
            return false;
        }
        str = str.trim();
        let reg = /^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$/;
        return this.RegexMatch(reg, str);
    }

    /**
     * 验证是否为负数字 x<0
     * @param  str 待验证的字符串
     * @returns
     */
    public static IsNumberNegative(str: string): boolean {
        if (this.IsEmpty(str)) {
            return false;
        }
        str = str.trim();
        let reg = /^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$/;
        return this.RegexMatch(reg, str);
    }

    /**
     * 验证是否为正数字 x>=0
     * @param  str 待验证的字符串
     * @returns
     */
    public static IsNumberPositiveByZero(str: string): boolean {
        if (this.IsEmpty(str)) {
            return false;
        }
        str = str.trim();
        let reg = /^\d+(\.\d+)?$/;
        return this.RegexMatch(reg, str);
    }

    /**
     * 验证是否为负数字 x<=0
     * @param  str 待验证的字符串
     * @returns
     */
    public static IsNumberNegativeByZero(str: string): boolean {
        if (this.IsEmpty(str)) {
            return false;
        }
        str = str.trim();
        let reg = /^((-\d+(\.\d+)?)|(0+(\.0+)?))$/;
        return this.RegexMatch(reg, str);
    }

    /**
     * 验证小数位必需要有几位，不能没有小数位  eg:【1=false,1.=false,1.1=false,1.12=true,1.123=false】
     * @param str 待验证的字符串
     * @param n 小数位固定位数
     * @returns
     */
    public static HasPrecision(str: string, n: number = 2): boolean {
        if (this.IsEmpty(str)) {
            return false;
        }
        str = str.trim();
        let reg = new RegExp("^\\d+\\.\\d{" + n + "}?$");
        return this.RegexMatch(reg, str);
    }

    /**
     * 验证小数位不能小于且大于几位，可以没有小数位
     * @param str 待验证的字符串
     * @param max 最多几位小数
     * @param min 最少几位小数
     * @returns
     */
    public static MaxPrecision(str: string, max: number = 2, min: number = 1): boolean {
        if (this.IsEmpty(str)) {
            return false;
        }
        str = str.trim();
        let reg = new RegExp("^\\d+(\\.\\d{" + min + "," + max + "})?$");
        return this.RegexMatch(reg, str);
    }
    //#endregion

    //#region 日期与时间
    /**
     * 根据date值返回日期部分
     * @param date 时间值，为null时则为当前时间
     * @returns
     */
    public static GetDate(date?: string | Date | null): string {
        return this.FormatDate("YYYY-MM-DD", date);
    }

    /**
     * 根据date值返回时间部分
     * @param date 时间值，为null时则为当前时间
     * @returns
     */
    public static GetTime(date?: string | Date | null): string {
        return this.FormatDate("HH:mm:ss", date);
    }

    /**
     * 根据date值返回日期与时间部分
     * @param date 时间值，为null时则为当前时间
     * @returns
     */
    public static GetDateTime(date?: string | Date | null): string {
        return this.FormatDate("YYYY-MM-DD HH:mm:ss", date);
    }

    /**
     * 根据date值返回日期与时间部分，时间不返回秒
     * @param date 时间值，为null时则为当前时间
     * @returns
     */
    public static GetDateTimeHour(date?: string | Date | null): string {
        return this.FormatDate("YYYY-MM-DD HH:mm", date);
    }

    /**
     * 格式化日期
     * @param format 格式化的字符，参考moment.js
     * @param date 时间值，为null时则为当前时间
     * @returns
     */
    public static FormatDate(format?: string, date?: string | Date | null): string {
        date = date == null ? new Date() : date;
        return dayjs(date).format(format);
    }

    /**
     * 用于返回日期/时间的单独部分
     * @param datePart 指定日期部分
     * @param date 日期
     * @returns
     */
    public static GetDatePart(datePart: DatePart, date?: string | Date | null): number {
        date = date == null ? new Date() : date;
        let m: Dayjs = dayjs(date);

        let res: number = Number.MIN_VALUE;
        switch (datePart) {
            case DatePart.Year:
                res = m.year();
                break;
            case DatePart.Month:
                res = m.month() + 1;
                break;
            case DatePart.Day:
                res = m.date();
                break;
            case DatePart.Hour:
                res = m.hour();
                break;
            case DatePart.Minute:
                res = m.minute();
                break;
            case DatePart.Second:
                res = m.second();
                break;
            case DatePart.Millisecond:
                res = m.millisecond();
                break;
        }
        return res;
    }

    /**
     * 在日期中添加或减去指定的时间间隔
     * @param datePart 指定日期部分
     * @param val 值
     * @param date 日期
     * @param format 返回指定日期格式
     * @returns
     */
    public static DateAdd(datePart: DatePart, val: number, date?: string | Date | null, format: string = "YYYY-MM-DD HH:mm:ss"): string {
        date = date == null ? new Date() : date;
        let m: Dayjs = dayjs(date);

        switch (datePart) {
            case DatePart.Year:
                m = m.add(val, "year");
                break;
            case DatePart.Month:
                m = m.add(val, "month");
                break;
            case DatePart.Day:
                m = m.add(val, "day");
                break;
            case DatePart.Hour:
                m = m.add(val, "hour");
                break;
            case DatePart.Minute:
                m = m.add(val, "minute");
                break;
            case DatePart.Second:
                m = m.add(val, "second");
                break;
            case DatePart.Millisecond:
                m = m.add(val, "millisecond");
                break;
        }
        return m.format(format);
    }

    /**
     * 返回两个日期之间的时间差【结束日期 - 开始日期】
     * @param datePart 指定日期部分
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @returns
     */
    public static DateDiff(datePart: DatePart, startDate: string | Date, endDate: string | Date, returnFloat: boolean = false): number {
        let start: Dayjs = dayjs(startDate);
        let end: Dayjs = dayjs(endDate);

        let res: number = Number.MIN_VALUE;
        switch (datePart) {
            case DatePart.Year:
                res = end.diff(start, "year", returnFloat);
                break;
            case DatePart.Month:
                res = end.diff(start, "month", returnFloat);
                break;
            case DatePart.Day:
                res = end.diff(start, "day", returnFloat);
                break;
            case DatePart.Hour:
                res = end.diff(start, "hour", returnFloat);
                break;
            case DatePart.Minute:
                res = end.diff(start, "minute", returnFloat);
                break;
            case DatePart.Second:
                res = end.diff(start, "second", returnFloat);
                break;
            case DatePart.Millisecond:
                res = end.diff(start, "millisecond", returnFloat);
                break;
        }

        return res;
    }

    /**
     * 根据数据返回年月日
     * @param date 日期
     * @param nullValue 空值时显示内容
     * @returns
     */
    public static YMD(date?: string | Date | null, nullValue: string = "-"): string {
        let res: string = nullValue;
        if (date) {
            let d: Date = new Date(date);
            res = dayjs(d).format("YYYY-MM-DD");
        }
        return res;
    }

    /**
     * 根据数据返回年月日时分
     * @param date 日期
     * @param nullValue 空值时显示内容
     * @returns
     */
    public static YMDHM(date?: string | Date | null, nullValue: string = "-"): string {
        let res: string = nullValue;
        if (date) {
            let d: Date = new Date(date);
            res = dayjs(d).format("YYYY-MM-DD HH:mm");
        }
        return res;
    }
    //#endregion

    //#region 格式化数字
    /**
     * 格式化数字，始终保留n位小数，n为要保留的小数位，超出则四舍五入，小于则补0
     * @param num 待格式化的数字
     * @param n 保留小数位
     * @returns
     */
    public static FormatNumber(num: number | string, n: number): string {
        let resStr = num.toString();

        //当n>0时，说明要格式化成固定位数的小数形式
        if (n > 0) {
            let pos_decimal = resStr.indexOf(".");
            if (pos_decimal < 0) {
                //如果没有小数位，则给出小数点
                pos_decimal = resStr.length;
                resStr += ".";
            }

            //循环补0
            while (resStr.length <= pos_decimal + n) {
                resStr += "0";
            }
        }

        return resStr;
    }

    /**
     * 四舍五入数字，保留n位小数，小数位为0时则丢弃
     * @param num 待格式化的数字
     * @param n 保留小数位
     * @returns
     */
    public static GetRound(num: number, n: number): number {
        let t = Math.pow(10, n);
        return Math.round(num * t) / t;
    }

    /**
     * 保留n位小数，多余小数位向下取整
     * @param num 待格式化的数字
     * @param n 保留小数位
     * @returns
     */
    public static GetFloor(num: number, n: number): number {
        let t = Math.pow(10, n);
        return Math.floor(num * t) / t;
    }

    /**
     * 保留n位小数，多余小数位向上取整
     * @param num 待格式化的数字
     * @param n 保留小数位
     * @returns
     */
    public static GetCeil(num: number, n: number): number {
        let t = Math.pow(10, n);
        return Math.ceil(num * t) / t;
    }
    //#endregion

    //#region 随机数、文件
    /**
     * 得到一个范围内的随机数
     * @param min 范围最小值（包含）
     * @param max 范围最大值（包含）
     * @returns
     */
    public static GetRand(min: number, max: number): number {
        return Math.round(min + Math.random() * (max - min));
    }

    /**
     * 获取一个与时间相关的文件名
     * @param file 文件名
     * @returns
     */
    public static GenerateFileName(file: File): string {
        let fileInfo = this.GetUrlFileName(file.name);
        return fileInfo.fileName + "-" + new Date().getTime() + "." + fileInfo.extName;
    }

    /**
     * 下载文件
     * @param url 文件路径地址
     * @param name 文件名，不需要扩展名
     */
    public static DownloadFile(url: string, name?: string): void {
        let xhr = new XMLHttpRequest();
        xhr.open("GET", url, true);
        xhr.responseType = "blob";
        xhr.onload = () => {
            if (this.IsEmpty(name)) {
                let _fileInfo = this.GetUrlFileName(url);
                name = _fileInfo.fileName + "." + _fileInfo.extName;
            }
            saveAs(xhr.response, name);
        };
        xhr.send();
    }

    /**
     * 根据Url地址得到文件名信息
     * @param url Url地址
     * @returns
     */
    public static GetUrlFileName(url: string): UrlFile {
        let res: UrlFile = {
            fileName: url.substring(url.lastIndexOf("/") + 1, url.lastIndexOf(".")),
            extName: url.substring(url.lastIndexOf(".") + 1),
            fullName: url.substring(url.lastIndexOf("/") + 1),
        };
        return res;
    }

    /**
     * 完善ExtFile对象扩展属性
     * @param extData 至少包含 url 和 fileName 2个属性的对象
     * @returns
     */
    public static GetFileExtInfo(extData: FileExt): FileExt {
        //要求extData中应该是要有url和fileName这2个属性的值，也就是服务端保存的内容

        extData = this.DeepCopy(extData) as FileExt;

        let fileNameObj = Gx.GetUrlFileName(extData.url);
        extData.extName = fileNameObj.extName;
        extData.isImg =
            this.imageExts.findIndex((x) => {
                return x == fileNameObj.extName.toLowerCase();
            }) > -1;

        if (extData.isImg) {
            if (Config._UPLOAD_TYPE === UploadType.Local) {
                extData.displayUrl = Config._API_URL + extData.url;
            } else if (Config._UPLOAD_TYPE === UploadType.Qiniu) {
                extData.displayUrl = extData.url;
            } else {
                extData.displayUrl = null;
            }
        } else {
            extData.icon = extIcon[extData.extName] || extIcon["undefined"];
        }

        return extData;
    }

    /**
     * 完善ExtFileList集合中扩展属性
     * @param extDataList 至少包含 url 和 fileName 2个属性的对象集合
     * @returns
     */
    public static GetFileExtInfoList(extDataList: Array<FileExt>): Array<FileExt> {
        let res: Array<FileExt> = [];

        extDataList.forEach((item) => {
            res.push(this.GetFileExtInfo(item));
        });

        return res;
    }

    //#endregion
}

export default GxBase;
